package com.nio;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @Author 咕唧
 * @Date 2022/7/5 22:24
 * @Version 1.0
 * 群发消息
 */
public class Nio08Server {
    /**
     * 保存所有客户端的一个集合
     */
    private static List<SocketChannel> allClients = new ArrayList<>();

    public static void main(String[] args) throws Exception {
//搞一个selector
        Selector selector = Selector.open();
        //搞一个server channel
        ServerSocketChannel socketChannel = ServerSocketChannel.open();
        //绑定端口
        socketChannel.bind(new InetSocketAddress("10.9.48.142", 23456));
        //设置为非阻塞
        socketChannel.configureBlocking(false);
        //注册到selector,并且关注accept
        socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器启动了....");
        //循环
        while (true) {
            //首先我们要看看有没有事情发生,因为没有事情发生的话,没有必要继续做,
            //因为是阻塞的方法,所以有返回值的时候其实就代表有正常结果了,没有正常结果会一直阻塞,一直阻塞也就没有返回值
            int select = selector.select();
            //说明发生了我们感兴趣的事情
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            //遍历
            selectionKeys.forEach(selectionKey -> {
                //获取到了有操作的通道
                SelectableChannel channel = selectionKey.channel();
                //如果收到的是连接类型的操作
                if (selectionKey.isAcceptable()) {
                    try {
                        //接受连接请求,一旦接受,连接就会建立完成
                        SocketChannel accept = ((ServerSocketChannel) channel).accept();
                        //设置被阻塞
                        accept.configureBlocking(false);
                        //一旦建立连接后,当前的channel就会关注消息数据
                        //设置感兴趣的操作
                        accept.register(selector, SelectionKey.OP_READ);
                        //保存当前连接到集合
                        allClients.add(accept);
                        System.out.println("客户端" + accept.getRemoteAddress() + "建立连接了" + accept.getLocalAddress());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else if (selectionKey.isReadable()) {
                    //收到可以处理的消息了
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    while (true) {
                        byteBuffer.clear();
                        try {
                            int read = ((SocketChannel) channel).read(byteBuffer);
                            if (read > 0) {
                                byteBuffer.flip();
                                //读取消息
                                String msg = String.valueOf(Charset.forName("gbk").decode(byteBuffer));
                                msg = "客户端" + ((SocketChannel) channel).getRemoteAddress() + "发送的消息:===>" + msg;
                                System.err.println(msg);

                                //清空数据,替换为我们自己要发送的数据
                                byteBuffer.clear();
                                //把我们要发送的数据写进去
                                byteBuffer.put(msg.getBytes("gbk"));
                                //翻转
                                byteBuffer.flip();
                                //发送给其他客户端
                                allClients.forEach(socketChannel1 -> {
                                    //不给自己发送
                                    if (!socketChannel1.equals(channel)) {
                                        try {
                                            //进入重新读的状态,因为每一个客户端都要发一次,所以每次都要重置一下,不然就会被之前的占用光了
                                            byteBuffer.rewind();
                                            socketChannel1.write(byteBuffer);
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                });

                            } else {
                                //System.out.println("没有数据了");
                                break;
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            });
            //清理已经发生的事情，等待下次事情发生
            selectionKeys.clear();

        }
    }
}
